#include "EdgeDetector.h"
#include <stdexcept>

/**
 * @brief 检查输入图像是否有效
 */
bool EdgeDetector::IsValidImage(const cv::Mat& src) {
    // 图像非空，并且是灰度或彩色图像
    return !src.empty() && (src.channels() == 1 || src.channels() == 3);
}

/**
 * @brief Canny 边缘检测
 */
cv::Mat EdgeDetector::CannyDetect(const cv::Mat& src,
                                  double threshold1,
                                  double threshold2,
                                  int apertureSize,
                                  bool L2gradient) {
    if (!IsValidImage(src)) {
        throw std::invalid_argument("CannyDetect: Invalid input image.");
    }

    cv::Mat gray, edges;

    // 如果是彩色图像，先转为灰度
    if (src.channels() == 3) {
        cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    } else {
        gray = src.clone();
    }

    // 调用 OpenCV 的 Canny 算法
    cv::Canny(gray, edges, threshold1, threshold2, apertureSize, L2gradient);
    return edges;
}

/**
 * @brief Sobel 边缘检测
 */
cv::Mat EdgeDetector::SobelDetect(const cv::Mat& src,
                                  int dx,
                                  int dy,
                                  int ksize,
                                  double scale,
                                  double delta) {
    if (!IsValidImage(src)) {
        throw std::invalid_argument("SobelDetect: Invalid input image.");
    }

    cv::Mat gray, grad;

    // 转灰度
    if (src.channels() == 3) {
        cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    } else {
        gray = src.clone();
    }

    // Sobel 计算 x 和 y 方向的梯度
    cv::Mat gradX, gradY;
    cv::Sobel(gray, gradX, CV_16S, dx, 0, ksize, scale, delta);
    cv::Sobel(gray, gradY, CV_16S, 0, dy, ksize, scale, delta);

    // 转换为 8 位图像
    cv::Mat absGradX, absGradY;
    cv::convertScaleAbs(gradX, absGradX);
    cv::convertScaleAbs(gradY, absGradY);

    // 将两个方向的结果融合
    cv::addWeighted(absGradX, 0.5, absGradY, 0.5, 0, grad);

    return grad;
}

/**
 * @brief Laplacian 边缘检测
 */
cv::Mat EdgeDetector::LaplacianDetect(const cv::Mat& src,
                                      int ksize,
                                      double scale,
                                      double delta) {
    if (!IsValidImage(src)) {
        throw std::invalid_argument("LaplacianDetect: Invalid input image.");
    }

    cv::Mat gray, lap;

    // 转灰度
    if (src.channels() == 3) {
        cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    } else {
        gray = src.clone();
    }

    // Laplacian 计算
    cv::Mat lap16S;
    cv::Laplacian(gray, lap16S, CV_16S, ksize, scale, delta);

    // 转换为 8 位图像
    cv::convertScaleAbs(lap16S, lap);

    return lap;
}
